﻿using System;
using System.Net;
using System.IO;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Text;
using System.Collections.Generic;
using System.Collections;

namespace QD.Utill
{
    public class HttpHtmlModel
    {
        public HttpHtmlModel()
        {
            Html = ResponseUrl = ErrorMessage = string.Empty;
        }
        public string Html { get; set; }
        public string ResponseUrl { get; set; }
        public string ErrorMessage { get; set; }
        /// <summary>
        /// 返回代码 200 正常, 500 错误
        /// </summary>
        public int Code { get; set; }
    }

    public class HttpRequest
    {
        public string Referer { get; set; }
        public string UserAgent { get; set; }
        public ICredentials Credentials = null;
        public CookieContainer m_Cookie = new CookieContainer();
        public Encoding Encode { get; set; }
        IWebProxy Proxy { get; set; }

        public int Timeout { get { return 10000; } }

        public HttpRequest()
        {
            Encode = Encoding.UTF8;
        }

        public HttpRequest(string UserAgent, string Referer)
        {
            Encode = Encoding.UTF8;
            this.UserAgent = UserAgent;
            this.Referer = Referer;
        }

        /// <summary>
        /// GET请求
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public string Requset(string url)
        {
            string html = string.Empty;
            Requset(url, out html);
            return html;
        }

        /// <summary>
        /// GET请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="html">返回的HTML</param>
        /// <returns></returns>
        public string Requset(string url, out string html)
        {
            string msg = string.Empty;
            HttpWebRequest request = CreateRequest(url);
            SetRequest(request, "GET");
            try
            {
                using (WebResponse res = request.GetResponse())
                {
                    using (StreamReader read = new StreamReader(res.GetResponseStream(), Encode))
                    {
                        html = read.ReadToEnd();
                    }
                }
            }
            catch (Exception ex) { html = ""; msg = ex.Message; }
            finally { if (request != null) request.Abort(); GC.Collect(); }
            return msg;
        }

        public HttpHtmlModel RequsetObj(string url)
        {
            var htmlModel = new HttpHtmlModel();
            HttpWebRequest request = request = CreateRequest(url);
            SetRequest(request, "GET");
            try
            {
                using (var res = (HttpWebResponse)request.GetResponse())
                {
                    htmlModel.Code = (int)res.StatusCode;
                    htmlModel.ResponseUrl = res.ResponseUri.ToString();
                    using (var read = new StreamReader(res.GetResponseStream(), Encode))
                    {
                        htmlModel.Html = read.ReadToEnd();
                    }
                }
            }
            catch (Exception ex) { htmlModel.Code = 500; htmlModel.Html = htmlModel.ErrorMessage = ex.Message; }
            finally
            {
                if (request != null) request.Abort();
                GC.Collect();
            }
            return htmlModel;
        }

        /// <summary>
        /// 针对百度截图的各项优化
        /// </summary>
        /// <param name="url"></param>
        /// <param name="html"></param>
        /// <returns></returns>
        public string Request_BD(string url, out string html) {
            string msg = string.Empty;
            HttpWebRequest request = null;
            try
            {
                request = CreateRequest(url);
                SetRequest(request, "GET");
                //响应流
                using (WebResponse res = request.GetResponse())
                {
                    SetCookies_BD(GetAllCookies(m_Cookie, (res as HttpWebResponse).Cookies));
                    using (StreamReader read = new StreamReader(res.GetResponseStream(), Encode))
                    {
                        html = read.ReadToEnd();
                    }
                }
            }
            catch (Exception ex) { html = ""; msg = ex.Message; }
            finally { if (request != null) request.Abort(); GC.Collect(); }
            return msg;
        }

        /// <summary>
        /// 发送POST远程请求，返回UTF-8编码的响应流
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param">格式如：name=Encode("name")&email=Encode("email")</param>
        /// <returns>错误消息</returns>
        public string RequestPost(string url, string param)
        {
            string html = string.Empty;
            byte[] data = Encode.GetBytes(param);
            HttpWebRequest request = null;
            try
            {
                request = CreateRequest(url);
                SetRequest(request, "POST");
                request.ReadWriteTimeout = 10000;
                request.ContentLength = data.Length;
                request.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

                //请求流,发送POST参数
                if (data.Length > 0)
                {
                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                        // reqStream.Close();
                    }
                }

                //响应流
                using (WebResponse response = request.GetResponse())
                {
                    using (StreamReader read = new StreamReader(response.GetResponseStream(), Encode))
                    {
                        html = read.ReadToEnd();
                    }
                }

                //设置服务器返回的Cookie
                string cookieheader = request.CookieContainer.GetCookieHeader(new Uri(url));
                m_Cookie.SetCookies(new Uri(url), cookieheader);
            }
            catch (Exception ex) { html = ""; }
            finally { if (request != null) request.Abort(); GC.Collect(); }
            return html;
        }

        /// <summary>
        /// 添加Cookie
        /// </summary>
        /// <param name="cookie"></param>
        public void AddCookie(Cookie cookie)
        {
            m_Cookie.Add(cookie);
        }

        /// <summary>
        /// 添加Cookie
        /// </summary>
        public void AddCookie(string name, string value, string domain, DateTime expires)
        {
            Cookie cookie = new Cookie(name, value);
            cookie.Domain = domain;
            cookie.Expires = expires;
            m_Cookie.Add(cookie);
        }
        /// <summary>
        /// 清空Cookie
        /// </summary>
        public void ClearCookie()
        {
            m_Cookie = null;
            m_Cookie = new CookieContainer();
        }
        public void AppendUserAgent(string appendStr)
        {
            UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" + appendStr;
        }

        /// <summary>
        /// 设置代理
        /// </summary>
        public void SetProxy(string IP, int port)
        {
            Proxy = new WebProxy(IP, port);
        }
        
        public Stream GetReposeStream(string url, out string msg)
        {
            msg = "";
            Stream stream = null;
            try
            {
                HttpWebRequest request = CreateRequest(url);
                SetRequest(request, "GET");
                WebResponse response = request.GetResponse();
                stream = response.GetResponseStream();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }
            return stream;
        }

        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受 
        }

        private HttpWebRequest CreateRequest(string url)
        {
            HttpWebRequest request = null;
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                //HTTPS请求
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
                request = (HttpWebRequest)WebRequest.Create(url);   //HTTP请求
            return request;
        }

        /// <summary>
        /// 设置请求的参数
        /// </summary>
        private void SetRequest(HttpWebRequest request, string Method)
        {
            request.Method = Method;
            request.Timeout = Timeout;
            request.CookieContainer = m_Cookie;
            request.Referer = Referer;
            request.UserAgent = UserAgent;
            request.AllowAutoRedirect = true;
            request.AllowWriteStreamBuffering = false;
            request.KeepAlive = true;
            request.ContentType = "application/x-www-form-urlencoded;charset=utf-8";

            if (Proxy != null)
                request.Proxy = Proxy;  //代理

            //request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
            //request.KeepAlive = true;
            //request.ContentLength = 0;
            //request.KeepAlive = true;
            //request.ContentType = "application/octet-stream";
        }


        /// <summary>
        /// 两个cookie取合值
        /// </summary>
        /// <param name="cc"></param>
        /// <param name="cc2"></param>
        /// <returns></returns>
        public List<Cookie> GetAllCookies(CookieContainer cc,CookieCollection cc2)
        {
            List<Cookie> lstCookies = new List<Cookie>();
            //取第一个集合
            Hashtable table = (Hashtable)cc.GetType().InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cc, new object[] { });
            foreach (object pathList in table.Values)
            {
                SortedList lstCookieCol = (SortedList)pathList.GetType().InvokeMember("m_list", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, pathList, new object[] { });
                foreach (CookieCollection colCookies in lstCookieCol.Values)
                    foreach (Cookie c in colCookies)
                    {
                        if (lstCookies.Contains(c))
                            lstCookies.Remove(c);
                        lstCookies.Add(c);
                    }
            }
            foreach (Cookie ck in cc2) {
                if (lstCookies.Contains(ck))
                    lstCookies.Remove(ck);
                lstCookies.Add(ck);
            }
            return lstCookies;
        }

        /// <summary>
        /// 百度的cookie赋值
        /// </summary>
        /// <param name="lstCookie"></param>
        public void SetCookies_BD(List<Cookie> lstCookie) {
            ClearCookie();
            foreach (Cookie cke in lstCookie)
                m_Cookie.Add(cke);
        }
    }
}